package com.caipiao.lottery.lty.server;

import java.util.Properties;

import com.caipiao.lottery.config.Config;
import com.caipiao.util.BizException;
import com.caipiao.util.IdMaker;
import com.caipiao.util.StringTools;
import com.caipiao.lottery.log.TraceLogger;
import com.caipiao.lottery.lty.handler.LtyHandler;
import com.caipiao.lottery.lty.handler.LtyHandlerHelper;
import com.caipiao.lottery.lty.message.LtyMsgBodyFactory;
import com.caipiao.lottery.lty.message.LtyRequest;
import com.caipiao.lottery.lty.message.LtyResponse;
import com.caipiao.lottery.lty.message.MessageCodeHelper;
import com.caipiao.lottery.lty.message.MessageRequest;
import com.caipiao.lottery.lty.message.MessageResponseCommon;
import com.caipiao.lottery.core.ErrorDef;
import com.caipiao.lottery.lty.handler.LtyHandlerFactory;
//处理句柄接口
public class LtyMsgHandler
{	
	public String Process(String ReqString, HandlerResult handler_result, String productId, String channelId, String version, String cmd)
	{
		StringBuffer log_buff = handler_result.log_buff;
		
		//增加引用计数
		startReq();
		try
		{
			LtyRequest ltyReq = new LtyRequest();

			//解析包头
			try
			{
				ltyReq = (LtyRequest) ltyReq.ParseFromString(ReqString);
				
				if (null == ltyReq)
				{
					throw new BizException("解析空对象");
				}
				
				ltyReq.cmd = cmd;
				ltyReq.productId = productId;
				ltyReq.channelId = channelId;
				
				//缺省渠道
				if (null == ltyReq.channelId || ltyReq.channelId.isEmpty())
				{
					ltyReq.channelId = "default";
				}
				
				ltyReq.version = version;
			}
			catch(Exception e)
			{
				log_buff.append("包头报文解析异常");
				TraceLogger.Lty.warn("Req包头解析异常:" + e + ", 原始报文:" + ReqString);
				return "";
			}
			
			//调试用
			if (null == ltyReq.msgId || ltyReq.msgId.isEmpty())
			{
				ltyReq.msgId = IdMaker.Get_MSG_Id();
			}
	
			log_buff.append(ltyReq.msgId + " 产品:" + ltyReq.productId  + " 请求接口:" + ltyReq.cmd);
			
			//包头数据包格式校验
			try
			{
				ltyReq.CheckParam();
			}
			catch(Exception e)
			{
				log_buff.append("包头报文校验异常");
				TraceLogger.Lty.warn(ltyReq.msgId +"Req包头校验异常:" + e);
				return "";
			}
			
			TraceLogger.Lty.trace(log_buff +" - Req包头解析成功");
			
			//接口配置
			Properties interface_prop = Config.Interface.GetPropById(ltyReq.cmd);
			
			log_buff.append(" - " + interface_prop.getProperty("Cmd.Desc", ""));
    		
			//响应数据
    		LtyResponse ltyResp = new LtyResponse();
    		
    		String DataMode = "";
    		
			//加密密钥
			String aesKey =  Config.Product.GetPropValue("Cipher.KeyValue", ltyReq.keyId);
    		
    		//日志用	
    		do
    		{
    			String CmdEnable = interface_prop.getProperty("Cmd.Enable", "");
    			
    			if (!CmdEnable.equalsIgnoreCase("1"))
    			{
    				TraceLogger.Lty.warn(log_buff + " - 不支持的接口请求");
    				ltyResp.result = ErrorDef.PAM_ERROR;
    				break;
    			}
    			
    			//接口指定固定错误码
    			if (interface_prop.getProperty("Cmd.ErrorControl", "").equalsIgnoreCase("1"))
    			{
    				TraceLogger.Lty.warn(log_buff + " - 接口配置返回指定错误码");
    				ltyResp.result = interface_prop.getProperty("Cmd.ErrorCode", "-1");
					break;
    			}

    			DataMode = interface_prop.getProperty("Cmd.DataMode");
    			
    			//接口数据模式检查
    			if (DataMode.indexOf(ltyReq.mode) < 0)
    			{
    				TraceLogger.Lty.warn(log_buff + " - 不支持的数据加密模式");
    				ltyResp.result = ErrorDef.PAM_ERROR;
					break;
    			}
    			
    			TraceLogger.Lty.trace(log_buff + " - 接口访问权限检查通过");
    			
    			/*
    			 * Session检查开始
    			 */
    			
    			try
    			{
	    			int SessionCheck = Integer.valueOf(interface_prop.getProperty("Cmd.CheckSession", "2"));
	    			
	    			TraceLogger.Lty.trace(log_buff + " - Session校验级别:" + SessionCheck);
	    			
	    			String sid = "";
    				String ssign = "";
    				
    				if (null != ltyReq.session && !ltyReq.session.isEmpty())
    				{
    					String[] session_ = ltyReq.session.split("[$]");
    					if (session_.length >= 1)
    					{
    						sid = session_[0];
    					}

    					if (session_.length >= 2)
    					{
    						ssign = session_[1];
    					}
    				}
	
	    			//需要获取Session
	    			if (SessionCheck >= 1)
	    			{
//	    				ltyReq.sessionData = SessionManager.Instance().GetSessionBySid(ltyReq.msgId, sid);
	    				
	    				if (null != ltyReq.sessionData)
	    				{
	    					log_buff.append(" uid:" + ltyReq.sessionData.userId);
	    				}
	    				
	    				//需要校验Session
	    				if (SessionCheck >= 2)
	    				{
	    					if (ltyReq.deviceId.isEmpty())
	    					{
	    						TraceLogger.Lty.warn(log_buff + " - 设备编号为空");
	    	    				//ltyResp.result = ErrorDef.PAM_ERROR;
	    						//break;
	    					}
	    					
	    					if (null == ltyReq.sessionData)
	    					{
	    						TraceLogger.Lty.warn(log_buff + " - 接口需要校验Session,未找到对应Session数据");
	    						ltyResp.result = ErrorDef.SESSION_ERROR;
								break;
	    					}
	
	    					//验签明文
							String mingData = ltyReq.cmd + ltyReq.deviceId + ltyReq.sessionData.sid + ltyReq.sessionData.skey + ltyReq.digest;
							
							//签名
							String sessionSign =  StringTools.MD5EncodeToHex(mingData);
							
							//签名异常
							if (!sessionSign.equalsIgnoreCase(ssign))
							{
								TraceLogger.Lty.warn(log_buff + " - 签名校验失败,传入签名:" + ssign + ",计算签名:" + sessionSign);
								ltyResp.result = ErrorDef.SESSION_ERROR;
								break;
							}
							
							TraceLogger.Lty.trace(log_buff + " - Session检查通过");
							
							//验证投注功能开通情况
							if (SessionCheck >= 3)
							{
								if (ltyReq.sessionData.ypt_invest_id.isEmpty())	//投注帐号为空
								{
									TraceLogger.Lty.warn(log_buff + "用户未开通投注帐号");
									ltyResp.result = ErrorDef.UNABLE_INVEST_ID;
									break;
								}

								if (SessionCheck != 4)		//4时不校验竞彩投注功能开通
								{
									if (!ltyReq.sessionData.ypt_jc_invest_state.equalsIgnoreCase("1"))		//未开通竞彩投注功能
									{
										TraceLogger.Lty.warn(log_buff + "用户未开通竞彩投注功能");
										ltyResp.result = ErrorDef.UNABLE_JC_FUNCTION;
										break;
									}
								}
							}
							
							//检查是否需要检查投注帐号状态
							String CheckInvestState = interface_prop.getProperty("Cmd.CheckInvestState", "");
							if (CheckInvestState.equalsIgnoreCase("1"))
							{
								if (!ltyReq.sessionData.ypt_invest_status.equalsIgnoreCase("0"))	//非正常状态
								{
									TraceLogger.Lty.warn(log_buff + "用户投注帐号处于异常状态:" + ltyReq.sessionData.ypt_invest_status);
									
									ltyResp.result = ErrorDef.SYS_SUCESS;
									
									ltyResp.bodyMsg = LtyMsgBodyFactory.GetLtyRespBody(ltyReq.cmd);
									
									if (ltyResp.bodyMsg != null && ltyResp.bodyMsg instanceof MessageResponseCommon)
				    				{
										MessageResponseCommon common_resp_body = (MessageResponseCommon)ltyResp.bodyMsg;
			    						
			    						common_resp_body.result = ErrorDef.INVEST_ID_STATUS_EXP + ltyReq.sessionData.ypt_invest_status;
			    						break;
				    				}
								}
							}
	    				}
	    				
	    				//心跳
						TraceLogger.Lty.debug(log_buff + " 加入异步心跳 ");
//	    				SessionManager.Instance().HeartBeat(ltyReq.msgId, productId, ltyReq.deviceId, ltyReq.sessionData);
	    			}
					/*
	    			else		//不需要获取Session
	    			{
	    				//心跳
	    				SessionManager.Instance().HeartBeat(ltyReq.msgId, productId, ltyReq.deviceId, ltyReq.sessionData);
	    			}
	    			*/
    			}
    			catch(Exception e)
    			{
    				TraceLogger.Lty.warn(log_buff + " - Session检查异常:" + e.toString());
					ltyResp.result = ErrorDef.SESSION_ERROR;
					break;
    			}

    			//解密请求包
    			
    			String mingReqBody = "";
    			try
    			{
    				mingReqBody =  MessageCodeHelper.DecodeBody(ltyReq.msgId,
    																							ltyReq.mode,
    																							ltyReq.body,
    																							aesKey,
    																							TraceLogger.LtyBin);
    				
        			TraceLogger.Lty.trace(log_buff +" - Req包体解密成功");
    			}
    			catch(Exception e)
    			{
    				TraceLogger.Lty.warn(log_buff + " - Req包体解密异常:" + e + "|KEY:" +aesKey + "解密前包体报文:" + ltyReq.body);
    				ltyResp.result = ErrorDef.DEC_ERROR;
    				break;
    			}
    			
    			//日志解密后的数据
    			TraceLogger.LtyBin.info(log_buff + " - Req包体解密结果:\n" + mingReqBody);
    			
    			if (!mingReqBody.isEmpty())
    			{
	    			//获取请求包体对象
	    			ltyReq.bodyMsg = LtyMsgBodyFactory.GetLtyReqBody(ltyReq.cmd);
	    			
	    			if (null == ltyReq.bodyMsg)
	    			{
	    				//程序错误
	    				TraceLogger.Lty.error(log_buff + " - Req包体结构未定义,接口实现错误");
	    				ltyResp.result = ErrorDef.SYS_ERROR;
	    				break;
	    			}
		
	    			//解析包体
	    			try
					{
	    				ltyReq.bodyMsg = (MessageRequest) ltyReq.bodyMsg.ParseFromString(mingReqBody);	//解析包体
	    				
	    				if (null == ltyReq.bodyMsg)
	    				{
	    					throw new BizException("包体解析为空");
	    				}
	    				
						TraceLogger.Lty.trace(log_buff + " - Req包体解析成功");
					} 
	    			catch (Exception e)
					{
						// TODO Auto-generated catch block
						TraceLogger.Lty.warn(log_buff + " - Req包体解析异常:" + e + ",包体报文:" + mingReqBody);
						ltyResp.result = ErrorDef.PAM_ERROR;
						break;
					}
	    			
	    			//校验包体
	    			try
	    			{
	    				ltyReq.bodyMsg.CheckParam();
	    				TraceLogger.Lty.trace(log_buff + " - Req包体参数校验成功");
	    			}
	    			catch (Exception e)
	    			{
	    				TraceLogger.Lty.warn(log_buff + " - Req包体参数校验失败:"+e.toString(), e);
	    				ltyResp.result = ErrorDef.PAM_ERROR;
	    				break;
	    			}
    			}
    			
    			//获取处理句柄
    			LtyHandler handler = LtyHandlerFactory.CreateHandler(ltyReq.cmd);
    			if (null == handler)	//空句柄
    			{
    				//返回参数错误    				
    				TraceLogger.Lty.warn(log_buff + " - 未实现的处理命令");
    				ltyResp.result = ErrorDef.SYS_ERROR;
    				break;
    			}
    			
    			//解析正常,处理请求	
    			try
    			{
    				ltyResp.result = handler.DoProcess(ltyReq, ltyResp);
    				
    				TraceLogger.Lty.trace(log_buff + " - 请求句柄处理完成");
    			} catch(Exception e) {
    				TraceLogger.Lty.error(log_buff + " 句柄处理异常:"+e.toString(),e);
    				
    				if (ltyResp.result.isEmpty())
    				{
    					ltyResp.result = ErrorDef.SYS_ERROR;//程序异常
    				}

    				break;
    			}
    		}
    		while(false);
    		
    		String head_error_code = ltyResp.result;
    		
    		//错误码转换
    		ltyResp.result = LtyHandlerHelper.GetErrorCode(head_error_code);		//包头
    		
    		TraceLogger.Lty.trace(log_buff + " - Head ErrorCode转换:" + head_error_code + " | " + ltyResp.result);
    		
    		String body_result_log = "";
    				
    		//导出响应包体数据
    		if (ltyResp.result.equalsIgnoreCase("0"))
    		{
    			if (null == ltyResp.mingBodyStr || ltyResp.mingBodyStr.isEmpty())
    			{
    				if (ltyResp.bodyMsg != null)
    				{
    					if (ltyResp.bodyMsg instanceof MessageResponseCommon)
    					{
    						MessageResponseCommon common_resp_body = (MessageResponseCommon)ltyResp.bodyMsg;
    						
    						common_resp_body.result = LtyHandlerHelper.GetErrorCode(common_resp_body.result);		//包体错误码转换
    						
    						if (null == common_resp_body.resultDesc || common_resp_body.resultDesc.isEmpty())
    						{
    							common_resp_body.resultDesc = LtyHandlerHelper.GetErrorCodeDesc(ltyReq.cmd, common_resp_body.result);
    						}
    						
    						//日志用
    						body_result_log = " 包体返回:" + common_resp_body.result + " - " + common_resp_body.resultDesc;
    					
    						//包体返回非正常结果
    						if (!common_resp_body.result.equalsIgnoreCase("0")
    								&& common_resp_body.result.equalsIgnoreCase(ErrorDef.SYS_SUCESS))
    						{
    							handler_result.handler_result = false;
    						}
    					}
    					
        				try
    					{
        					ltyResp.mingBodyStr = ltyResp.bodyMsg.ToString();
    					}
        				catch (Exception e)
    					{
        					TraceLogger.Lty.error(log_buff + " " + "Resp包体导出数据异常:"+e.toString(), e);
    					}
    				}
    			}
    		}
    		else
    		{
    			handler_result.handler_result = false;
    		}
    		
    		String head_result = " 包头返回:" + ltyResp.result;
    		
    		//记录加密前数据Resp.decodeBody
    		TraceLogger.LtyBin.info(log_buff + head_result + " - Resp包体结果:\n" + ltyResp.mingBodyStr);
    		
    		//加密返回数据

    		if (ltyResp.result.equalsIgnoreCase("0"))	//正确返回才进行加密
    		{
    			String respMode = "";
    			
    			//计算加密用模式
    			int zipSize = Integer.valueOf(Config.Interface.GetPropValue("ZipSize"));
    			
    			boolean isNoCrypt = (DataMode.indexOf("1") >= 0);
    			
    			if (isNoCrypt)
    			{
    				if (ltyResp.mingBodyStr.length() < zipSize)
    				{
    					respMode = "1";
    				}
    				else
    				{
    					respMode = "2";
    				}
    			}
    			else
    			{    				
    				if (ltyResp.mingBodyStr.length() < zipSize)
    				{
    					respMode = "3";
    				}
    				else
    				{
    					respMode = "4";
    				}
    			}

    			try
    			{	
    				ltyResp.body = MessageCodeHelper.EncodeBody(ltyReq.msgId,
    																							respMode, 
    																							ltyResp.mingBodyStr,
    																							aesKey,
    																							TraceLogger.LtyBin);
    				
    				ltyResp.mode = respMode;
    				
        			TraceLogger.Lty.trace(log_buff + head_result +" - Resp包体加密成功");
    			}
    			catch(Exception e)
    			{
    				TraceLogger.Lty.warn(log_buff + head_result + " - Resp包体加密异常:" + e + "|KEY:" + aesKey
    						+ "加密前包体报文:" + ltyResp.mingBodyStr);
    			}
    		}
    		
    		//生成摘要
    		ltyResp.digest = StringTools.MD5EncodeToHex(ltyResp.body);
    		
    		//错误描述
			String resultDesc = LtyHandlerHelper.GetErrorCodeDesc(ltyReq.cmd, ltyResp.result);

			if (body_result_log.isEmpty())
			{
				//日志用
				log_buff.append(head_result + " / " + ltyResp.result + " - " + resultDesc);
			}
			else
			{
				log_buff.append(body_result_log);
			}
			
    		try
			{
				return ltyResp.ToString(); 	//返回响应
			}
    		catch (Exception e)
			{
    			TraceLogger.Lty.warn(log_buff + " - 生成响应数据异常");
    			
    			return "";
			}	
		}
		finally
		{
			//减少引用计数
			endReq();
		}
	}
	
	static long Req_Count = 0;			//瞬时用户请求数
	static long Req_Over_Count = 0;		//完成用户请求数
	
	//计数锁
	static byte[] lock = new byte[0];
	
	public static void startReq()
	{
		synchronized(lock)
		{
			Req_Count++;
		}
	}
	
	public static void endReq()
	{
		synchronized(lock)
		{
			Req_Count--;
			Req_Over_Count++;
		}
	}
	
	public static long Get_Req_Count()
	{
		return Req_Count;
	}
	
	public static long Get_Req_Over_Count()
	{
		return Req_Over_Count;
	}
}


